﻿#include <stdio.h>
#include "sys_plat.h"
#include "pcap.h"
#include "net.h"
#include "netif_pacp.h"
#include "debug.h"
#include "nlist.h"
#include "nlocker.h"
#include "mblock.h"
#include "pktbuf.h"
#include "nlocker.h"
#include "tools.h"
#include "timer.h"
#include "ipv4.h"
#include "exmsg.h"
#include "ping/ping.h"
#include "socket.h"
#include "net_api.h"
#include "echo/udp_echo_client.h"
#include "echo/udp_echo_server.h"

// 打印 pcap_print
// 发送 pcap_inject //失败返回 -1
// 接收 pcap_next_ex //成功返回 1
// 内存拷贝 pcap_memcpy
// 创建线程 sys_thread_create
// sys_sem_wait sys_sem_notify

#define MAIN_DBG_LEVEL DBG_LEVEL_ERROR

// static nlocker_t locker;

typedef struct _test_node_t
{
	int idx;
	nlist_node_t node;
} test_node_t;

/**
 * @brief 测试链表
 */
void test_list()
{
#define NODES_NUM 5
	test_node_t nodes[NODES_NUM];
	nlist_t *tlist = (nlist_t *)malloc(sizeof(nlist_t));
	nlist_init(tlist);

	for (int i = 0; i < NODES_NUM; ++i)
	{
		nodes[i].idx = i;
		nlist_node_init(&nodes[i].node);
	}

	plat_printf("==========nlist is empty=============\n");
	if (nlist_is_empty(tlist))
	{
		plat_printf("nlist_is_empty is ok!\n");
	}
	else
	{
		plat_printf("nlist_is_empty has some error!\n");
	}
	plat_printf("==============end====================\n");

	plat_printf("============insert_first=============\n");
	for (int i = 0; i < NODES_NUM; ++i)
	{
		nlist_insert_first(tlist, &nodes[i].node);
	}
	plat_printf("nlist count = %d\n", nlist_count(tlist));

	// 我现在要的是什么？ 要的是指向节点指针的地址
	test_node_t *tmp = nlist_entry(test_node_t, node, &nodes[0].node);
	plat_printf("****id = %d******\n", tmp->idx);
	nlist_node_t *curr_p = NULL;
	nlist_for_each_reverse(curr_p, tlist)
	{
		plat_printf("node_id = %d\n", nlist_entry(test_node_t, node, curr_p)->idx);
	}

	plat_printf("******************\n");
	nlist_for_each(curr_p, tlist)
	{
		plat_printf("node_id = %d\n", nlist_entry(test_node_t, node, curr_p)->idx);
	}

	// for(curr_p = tlist->last; curr_p != tlist->first; curr_p = curr_p->pre){
	// 	test_node_t* tmp_1 = nlist_entry(test_node_t, node, curr_p);
	// 	plat_printf("node_id = %d\n", tmp_1->idx);
	// }
	plat_printf("=============end=====================\n");

	plat_printf("\n\n=============nlist_remove================\n");
	nlist_remove(tlist, &nodes[2].node);
	nlist_remove_first(tlist);
	nlist_remove_last(tlist);
	nlist_for_each(curr_p, tlist)
	{
		plat_printf("node_id = %d\n", nlist_entry(test_node_t, node, curr_p)->idx);
	}
	plat_printf("\n\n");
	nlist_for_each_reverse(curr_p, tlist)
	{
		plat_printf("node_id = %d\n", nlist_entry(test_node_t, node, curr_p)->idx);
	}

	plat_printf("\n***************\n");
	nlist_insert_last(tlist, &nodes[2].node);
	nlist_insert_after(tlist, &nodes[1].node, &nodes[4].node);
	nlist_for_each(curr_p, tlist)
	{
		plat_printf("node_id = %d\n", nlist_entry(test_node_t, node, curr_p)->idx);
	}
	plat_printf("\n\n");
	nlist_for_each_reverse(curr_p, tlist)
	{
		plat_printf("node_id = %d\n", nlist_entry(test_node_t, node, curr_p)->idx);
	}

	plat_printf("=============end==================\n");
}

void test_block()
{
#define BLK_SIZE 100
#define BLK_CNT 10

	uint8_t buf[BLK_SIZE][BLK_CNT]; // 一个10个内存块， 每个内存块的大小为100字节;
	mblock_t mblock;
	mblock_init(&mblock, buf, BLK_SIZE, BLK_CNT, NLOCKER_NONE);

	nlist_node_t *p = NULL;
	// (&(mblock.free_list))->first;
	nlist_node_t *nodes_addr[BLK_CNT];
	int idx = 0;
	nlist_for_each(p, (&mblock.free_list))
	{
		nodes_addr[idx] = p;
		++idx;
	}

	printf("==========test block alloc===========\n");
	nlist_node_t *blk = mblock_alloc(&mblock, 0);
	plat_printf("blk addr = %p\n", blk);
	plat_printf("free cnt = %d\n", mblock_free_block_cnt(&mblock));
	blk = mblock_alloc(&mblock, 0);
	plat_printf("blk addr = %p\n", blk);
	plat_printf("free cnt = %d\n", mblock_free_block_cnt(&mblock));

	mblock_free(&mblock, blk);
	plat_printf("free cnt = %d\n", mblock_free_block_cnt(&mblock));
	printf("============end==================\n");

	mblock_destroy(&mblock);

	plat_printf("free block num = %d\n", nlist_count(&mblock.free_list));
}

void test_pktbuf()
{
	pktbuf_t *buf = pktbuf_alloc(256 * 3 + 100);
	plat_printf("================================================\n");
	for (int i = 0; i < 6; ++i)
	{
		pktbuf_add_header(buf, 50, false);
	}
	plat_printf("================================================\n");
	for (int i = 0; i < 6; ++i)
	{
		pktbuf_remove_header(buf, 50);
	}
	plat_printf("================================================\n\n\n");

	pktbuf_resize(buf, 908);
	pktbuf_resize(buf, 908 + 220);
	pktbuf_resize(buf, 908);
	pktbuf_resize(buf, 908 - 40);
	pktbuf_resize(buf, 40);
	pktbuf_resize(buf, 0);

	plat_printf("================================================\n\n\n");

	pktbuf_t *dst_buf = pktbuf_alloc(256 + 40);
	pktbuf_t *src_buf = pktbuf_alloc(256 + 100);
	pktbuf_join(dst_buf, src_buf);

	plat_printf("================================================\n\n\n");
	pktbuf_set_cont(dst_buf, 40);
	pktbuf_set_cont(dst_buf, 40 + 100);
	pktbuf_set_cont(dst_buf, 256);
	pktbuf_set_cont(dst_buf, 520);
	plat_printf("================================================\n\n\n");
	pktbuf_free(buf);
	pktbuf_free(dst_buf);

	buf = pktbuf_alloc(256);
	pktbuf_join(buf, pktbuf_alloc(200));
	pktbuf_join(buf, pktbuf_alloc(56));

	uint16_t nums[1000];
	for (int i = 0; i < 1000; ++i)
	{
		nums[i] = i;
	}

	pktbuf_reset_acc(buf);
	pktbuf_write(buf, (uint8_t *)nums, pktbuf_total_remain(buf));
	uint16_t read_buf[1000];
	pktbuf_reset_acc(buf);
	plat_memset(read_buf, 0, sizeof(read_buf));
	pktbuf_read(buf, (uint8_t *)read_buf, pktbuf_total_remain(buf), 1000);
	pktbuf_reset_acc(buf);
	if (plat_memcmp(read_buf, nums, pktbuf_total_remain(buf)))
	{
		plat_printf("the memory is not same! idx: %d\n", plat_memcmp(read_buf, nums, pktbuf_total_remain(buf) / 2));
	}

	plat_memset(read_buf, 0, sizeof(read_buf));
	pktbuf_seek(buf, 80);
	pktbuf_read(buf, (uint8_t *)read_buf, pktbuf_total_remain(buf) - 80, 1000);
	pktbuf_seek(buf, 300);
	plat_memset(read_buf, 0, sizeof(read_buf));
	pktbuf_read(buf, (uint8_t *)read_buf, pktbuf_total_remain(buf) - 80, 1000);

	dst_buf = pktbuf_alloc(200);
	pktbuf_seek(buf, 0);
	pktbuf_join(dst_buf, pktbuf_alloc(256));
	pktbuf_join(dst_buf, pktbuf_alloc(56));
	pktbuf_reset_acc(dst_buf);
	pktbuf_copy(dst_buf, buf, pktbuf_total_remain(buf));

	plat_memset(read_buf, 0, sizeof(read_buf));
	pktbuf_seek(buf, 0);
	pktbuf_seek(dst_buf, 0);
	pktbuf_read(dst_buf, (uint8_t *)read_buf, pktbuf_total_remain(buf), 1000);
	if (plat_memcmp(read_buf, nums, pktbuf_total_remain(buf)))
	{
		plat_printf("not equal!\n");
	}
	plat_printf("ret:%d\n", plat_memcmp(read_buf, nums, pktbuf_total_remain(buf)));

	pktbuf_seek(dst_buf, 0);
	pktbuf_fill(dst_buf, 'c', 100);
	pktbuf_seek(dst_buf, 0);
	uint8_t read_buff[1000];
	plat_memset(read_buff, 0, sizeof(read_buff));
	pktbuf_read(dst_buf, (uint8_t *)read_buff, pktbuf_total_remain(buf), 1000);
}

void test_tools()
{
	uint16_t num = 0x1234;
	plat_printf("num = %d\n", num);
	num = x_htons(num);
	// swap_u16(num);
	plat_printf("num = %d\n", num);
}

void test_net_api()
{
	struct x_in_addr addr1;
	addr1.addr_0 = 192;
	addr1.addr_1 = 168;
	addr1.addr_2 = 74;
	addr1.addr_3 = 2;
	char *ip_str1 = inet_ntoa(addr1);

	struct x_in_addr addr2;
	addr2.s_addr = inet_addr(ip_str1);

	struct x_in_addr addr3;
	inet_pton(AF_INET, ip_str1, &addr3);

	char ip_str2[16];
	inet_ntop(AF_INET, &addr1, ip_str2, 16);

	int s = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
}

static void t0_proc(net_timer_t *timer, void *arg)
{
	static int cnt = 1;
	plat_printf("t0 proc(), cnt = %d\n", cnt++);
}
static void t1_proc(net_timer_t *timer, void *arg)
{
	static int cnt = 1;
	plat_printf("t1 proc(), cnt = %d\n", cnt++);
}
static void t2_proc(net_timer_t *timer, void *arg)
{
	static int cnt = 1;
	plat_printf("t2 proc(), cnt = %d\n", cnt++);
}
static void t3_proc(net_timer_t *timer, void *arg)
{
	static int cnt = 1;
	plat_printf("t3 proc(), cnt = %d\n", cnt++);
}

void test_timers()
{
	static net_timer_t t0, t1, t2, t3;
	timer_add(&t2, "t2", t2_proc, NULL, 5000, NET_TIMER_RELOAD);
	timer_add(&t0, "t0", t0_proc, NULL, 8000, 0);
	timer_add(&t3, "t3", t3_proc, NULL, 12000, NET_TIMER_RELOAD);
	timer_add(&t1, "t1", t1_proc, NULL, 20000, NET_TIMER_RELOAD);

	// timer_remove(&t1);
	// timer_remove(&t2);

	// timer_check_tmo(300);
	// timer_check_tmo(100);
	// timer_check_tmo(900);
}

pcap_data_t netdev0_data = {
	.ip = netdev0_phy_ip, // 物理机的网卡ip地址
	.hwaddr = netdev0_hwaddr};

net_err_t netdev_init()
{
	DBG_INFO(DBG_MAIN_LEVEL, "open netdev!");

	netif_t *netif = netif_open("netif 0", &netdev_ops, &netdev0_data);
	if (!netif)
	{
		DBG_ERROR(DBG_LOOP_LEVEL, "open netif 0 failed!");
		return NET_ERR_SYS;
	}

	ipaddr_t ip, mask, gateway;
	ipaddr_from_str(&ip, netdev0_ip); // 协议栈的虚拟网卡的ip地址
	ipaddr_from_str(&mask, netdev0_mask);
	ipaddr_from_str(&gateway, netdev0_gw);
	netif_set_addr(netif, &ip, &mask, &gateway);

	netif_set_active(netif);

	display_netif_list();

	// test
	// pktbuf_t *buf = pktbuf_alloc(4000);
	// ipaddr_t dest_ip;
	// // ipaddr_from_str(&dest_ip, friend0_ip);
	// ipaddr_from_str(&dest_ip, "192.168.74.3");
	// netif_put_out(netif, buf, -1);
	// //ipv4_out(1, &dest_ip, &netif->ipaddr, buf);

	return NET_ERR_OK;
}

int main()
{
#if LOG_TO_FILE
	FILE *fp = NULL;
	char *filename = LOG_OUTPUT_PATH;
	fp = freopen(filename, "w+", stdout);
	if (NULL == fp)
	{
		fprintf(stderr, "ereror open dbg log path: %s!\n", filename);
		return;
	}
#endif

	net_init();
	// test_timers();
	net_start();

	// netif_pcap_open();
	netdev_init();

	udp_echo_server_thread_start(2000);
	udp_echo_client_start("127.0.0.1", 2000);
	//udp_echo_client_start(friend0_ip, 1000);


	ping_t ping;
	// ping_run(&ping, "8.8.8.", 4, 5000, 1000);
	char cmd[32];
	char param[32];
	while (1)
	{
		plat_printf(">>");
		scanf("%s%s", cmd, param);
		if (plat_strcmp(cmd, "ping") == 0 || plat_strcmp(cmd, "PING") == 0)
		{
			plat_memset(&ping, 0, sizeof(ping));
			ping_run(&ping, param, 4, 32, 1000);
		}

#if LOG_TO_FILE
		fflush(stdout);
#endif

		sys_sleep(1000);
	}

#if LOG_TO_FILE
	fclose(fp);
#endif
}

#if 0
static sys_sem_t global_sem;
static char global_queue[100];
static int write_index;
static int read_index;
static int count;
static sys_mutex_t mutex;
static sys_sem_t global_read_sem;
static sys_sem_t global_write_sem;
static int total;

void thread_entry_1(void *arg)
{
	// for (int i = 0; i < 1000000; ++i)
	// {
	// 	sys_mutex_lock(mutex);
	// 	++count;
	// 	sys_mutex_unlock(mutex);
	// }
	// plat_printf("thread1: count = %d\n", count);

	for(int i = 0; i < 2 * sizeof(global_queue); ++i){
		sys_sem_wait(global_write_sem, 0);
		global_queue[write_index++] = i;
		if(write_index >= sizeof(global_queue)) write_index = 0;
		plat_printf("thread1: write data: %d\n", i);
		sys_sem_notify(global_read_sem);
		//sys_sleep(100);
	}

	while (1)
	{
		// plat_printf("thread1: sys_sem_notify: %d\n", global_sem);
		// sys_sem_notify(global_sem);
		// plat_printf("the first thread: %s is running!\n", (char *)arg);
		// sys_sleep(1000);
	}
}

void thread_entry_2(void *arg)
{
	for(int i = 0; i < 2 * sizeof(global_queue); ++i){
		sys_sem_wait(global_read_sem, 0);
		char c = global_queue[read_index++];
		if(read_index >= sizeof(global_queue)) read_index = 0;
		plat_printf("thread2: read data: %d\n", c);
		sys_sleep(1000);
		sys_sem_notify(global_write_sem);
	}

	// for (int i = 0; i < 1000000; ++i)
	// {
	// 	sys_mutex_lock(mutex);
	// 	--count;
	// 	sys_mutex_unlock(mutex);
	// }
	// plat_printf("thread2: count = %d\n", count);
	while (1)
	{
		// sys_sem_wait(global_sem, 0);
		// plat_printf("%d\n", global_sem);
		// plat_printf("the second thread: %s is running!\n", (char *)arg);
		// sys_sleep(100);
	}
}

int main()
{
	count = 0;
	write_index = 0;
	read_index = 0;
	mutex = sys_mutex_create();
	global_read_sem = sys_sem_create(0);
	global_write_sem = sys_sem_create(sizeof(global_queue));
	sys_thread_create(thread_entry_1, "jdc");
	sys_thread_create(thread_entry_2, "zzy");
	global_sem = sys_sem_create(0);
	plat_printf("the first sem: %d\n", global_sem);

	pcap_t *pcap = pcap_device_open(netdev0_phy_ip, netdev0_hwaddr); // 有点像socket
	int num = 1;

	while (pcap)
	{
		static uint8_t buffer[1024]; // 存放发送和接收的数据
		plat_memset(buffer, 0, sizeof(buffer));
		plat_printf("begin test: %d\n", num++);
		static struct pcap_pkthdr *pkthdr;
		static const uint8_t *data;

		// for(int idx = 0; idx < sizeof(buffer); ++idx){
		// 	buffer[idx] = idx;
		// }

		if (pcap_next_ex(pcap, &pkthdr, &data) != 1)
		{
			continue;
		}

		plat_printf("===========\n");

		int length = pkthdr->len < sizeof(buffer) ? pkthdr->len : sizeof(buffer);
		plat_memcpy(buffer, data, length);
		buffer[0] = 0;
		buffer[1] = 1;
		buffer[2] = 2;

		if (pcap_inject(pcap, buffer, sizeof(buffer)) == -1)
		{
			plat_printf("send message failed!\n");
			break;
		}

		// sys_sleep(1000);
	}
}
#endif
